/*  
 *  Copyright 2006 Paul Jack.
 *
 *  This file is part of the Dex compiler suite. 
 *  
 *  Dex is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by the
 *  Free Software Foundation; either version 2 of the License, or (at your
 *  option) any later version.
 *  
 *  Dex is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 *  Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 */
package dex.compiler.parser;


/**
 * Base class for the "hidden" parser objects.
 * 
 * Originally the public <code>Parser</code> class implemented parsing
 * for every kind of node.  That was a little difficult to deal with,
 * so I broke up the giant parser into five separate parsers.  This
 * class is the base class of those five parsers.  This class and
 * its subclasses are package-protected to prevent them from showing
 * up in the public API.  ParseBase and its children should be 
 * considered implementation details, subject to change.
 */
class ParserBase {


	/**
	 * The input source for the parser.
	 */
	final protected Input input;

	
	
	/**
	 * Constructs a new parser.
	 * 
	 * @param config  the configuration for the new parser.
	 */
	public ParserBase(ParserConfig config) {
		if (config == null) {
			throw new IllegalArgumentException("config may not be null");
		}
		this.input = config.getInput();
	}
	
	
	/**
	 * Handles an exception.
	 * 
	 * @param msg  the error message to report
	 */
	protected void raise(String msg) {
		throw new ParseException(input.getPlace(), msg);
	}
	
	
	
	private static boolean isDexIdentifierPart(char ch) {
		return (ch == ':') || Character.isJavaIdentifierPart(ch);
	}
	

	/**
	 * Parses an identifier.
	 * 
	 * @return  the parsed identifier
	 */
	public String parseIdentifier() {
		char ch = input.skipAndRead();
		if (!Character.isJavaIdentifierStart(ch)) {
			raise("Expected identifier but got " + (int)ch);
			return "$error$";
		}
		StringBuilder result = new StringBuilder();
		result.append(ch);
		ch = input.peek();
		while ((ch != 0) && isDexIdentifierPart(ch)) {
			input.expect(ch);
			result.append(ch);
			if (result.length() > 256) {
				raise("Identifier too long.");
			}
			ch = input.peek();
		}
		return result.toString();
	}

	
	/**
	 * Convenience for testing a keyword.  Here keyword means a sequence
	 * of characters terminated by WordBreaks.  This is handy down in
	 * parseStatement.
	 */
	protected boolean testKeyword(String keyword) {
		input.skipAndPeek();
		return input.test(keyword, WordBreaks.INSTANCE);
	}
}
